#!/usr/bin/env python

import time
import serial

import __modem as modem

class Modem(serial.Serial):
    '''Model class
    
    @author Julot <andy.julot@gmail.com>
    @since Friday, February 17, 2012. 09:58 AM'''
    
    def __init__(self, *args, **kwargs):
        serial.Serial.__init__(self, *args, **kwargs)
        self._sms = modem.Sms(self)
    
    @property
    def sms(self):
        return self._sms
    
    @property
    def isExists(self):
        '''Get property of exists.
        
        @return boolean wether the modem existed.'''
        
        return self.hasOk(self.attention(''))
    
    def hasOk(self, value):
        '''Check value for string OK.
        
        @param string response from modem.
        @return boolean wether value contains OK or not.'''
        
        return 'OK' in value
    
    def attention(self, command, timeOut=1, prefixed=True):
        '''Send command to modem.
        
        @param string at command.
        @param integer timeout in second.
        @param boolean whether using AT prefix or not.
        @return string modem response.'''
        
        try:
            self.flush()
            if prefixed:
                self.write('AT%s\r\n' % command)
            else:
                self.write('%s\r\n' % command)
            value = ''
            startTime = time.time()
            while True:
                inWaiting = self.inWaiting()
                if inWaiting: value = value + self.read(inWaiting)
                if value.find('>') >= 0: break
                if value.find('OK') >= 0: break
                if value.find('ERROR') >= 0: break
                if (time.time() - startTime) > timeOut: break
        except: value = ''
        return value
    
    def echoOn(self):
        '''Turn echo on.
        
        @return boolean wether operation succeeds.'''
        
        return self.hasOk(self.attention('e1'))
    
    def echoOff(self):
        '''Turn echo off.
        
        @return boolean wether operation succeeds.'''
        
        return self.hasOk(self.attention('e0'))

    def changeMessageStorage(self, order='"ME","ME","ME"'):
        '''Change message storage.
        
        @param string message storage order.
        @return boolean wether operation succeeds.'''
        
        return self.hasOk(self.attention('+CPMS=%s' % order))
    
    def changeMode(self, mode=0):
        '''Change mode to PDU or Text.
        
        @param integer PDU mode. 0 = PDU mode, 1 = Text mode
        @return boolean wether mode changed.'''
        
        return self.hasOk(self.attention('+CMGF=%s' % mode))
    
    def _extractIndexFromMessage(self, value):
        '''Extract message index from cmgl response.
        
        @param string response or cmgl command from modem.
        @return integer message index in modem.'''
        
        value = value[value.find(':') + 2:]
        return value[:value.find(',')]
    
    def cmgl(self, status=4):
        '''Return dictionary of index->message from modem in pdu format.
        index is position of message in modem, so it valid for other modem
        operation such as delete.
        
        @param integer if mode = 0, string if mode = 1. See changeMode method.
        @return dict of index, message.'''
        
        self.flushInput()
        result = self.attention('+CMGL=%s' % status, 10)
        results = [x.strip() for x in result.split('\n')]
        if not self.hasOk(results): return {}
        found = False
        messages = {}
        index = None
        for result in results:
            if found and index:
                messages[index] = result[:-2]
                found = False
                index = None
            elif '+CMGL' in result:
                index = self._extractIndexFromMessage(result)
                found = True
        return messages
    
    def cmgd(self, index):
        '''Delete message from modem.
        
        @param integer index of message in modem.
        @return boolean wether operation succeeds.'''
        
        if self.hasOk(self.attention('+CMGD=%s' % index)):
            return True
        return False
    
    @classmethod
    def search(cls):
        '''Search modem.
        
        @return Modem object or None if not found.'''
        
        modem = None
        
        # @constant tuple baudrate for serial communication.
        baudrates = (115200, 57600, 38400, 19200, 9600, 4800, 2400, 1800, 1200)
        
        for port in range(1, 257):
            for baudrate in baudrates:
                if modem: modem.close()
                try:
                    modem = cls('COM%s' % port, baudrate=baudrate)
                    if modem.isExists:
                        s = 'Modem found on COM%s at %sbps'
                        return modem
                except: pass
        return None
    
if __name__ == '__main__':
    modem = Modem('COM5')
    print modem.echoOff()    